home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / dev / gui / FoxGuiSource.lha / FoxLibSource / Buttons.c < prev    next >
C/C++ Source or Header  |  2001-07-07  |  56KB  |  1,998 lines

  1. /* FoxGUI - The fast, flexible, free Amiga GUI system
  2.     Copyright (C) 2001 Simon Fox (Foxysoft)
  3.  
  4. This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  5. Foxysoft: www.foxysoft.co.uk      Email:simon@foxysoft.co.uk                */
  6.  
  7. /******************************************************************************
  8.  * Shared library code.  Cannot call functions which use exit() such as:
  9.  * printf(), fprintf()
  10.  *
  11.  * Otherwise:
  12.  * The linker returns "__XCEXIT undefined" and the program will fail.
  13.  * This is because you must not exit() a library!
  14.  *
  15.  * Also:
  16.  * proto/exec.h must be included instead of clib/exec_protos.h and
  17.  * __USE_SYSBASE must be defined.
  18.  *
  19.  * Otherwise:
  20.  * The linker returns "Absolute reference to symbol _SysBase" and the
  21.  * library crashes.  Presumably the same is true for the other protos.
  22.  ******************************************************************************/
  23.  
  24. #define __USE_SYSBASE
  25.  
  26. #include <proto/mathieeedoubbas.h>
  27. #include <stdarg.h>
  28. #include <ctype.h>
  29. #include <string.h>
  30.  
  31. #include <proto/intuition.h>
  32. #include <proto/graphics.h>
  33. #include "/FoxInclude/foxgui.h"
  34. #include "FoxGuiTools.h"
  35.  
  36. #define GUIWIN(b) ((GuiWindow*)b->button.UserData)
  37.  
  38. static BOOL StatusStored = FALSE;
  39.  
  40. static PushButton *FindPreviousButton(PushButton **Bptr)
  41.    {
  42.    BOOL Found = FALSE;
  43.    PushButton *p = Gui.GGLfirst, *pp = NULL;
  44.    Diagnostic("FindPreviousButton", ENTER, TRUE);
  45.    while(p)
  46.       {
  47.       if (p == *Bptr)
  48.          {
  49.          Found = TRUE;
  50.          break;
  51.          }
  52.       else
  53.          {
  54.          pp = p;
  55.          p = p->Next;
  56.          }
  57.       }
  58.    if (!Found)
  59.       {
  60.       *Bptr = p = pp = NULL;
  61.       Diagnostic("FindPreviousButton", EXIT, FALSE);
  62.       }
  63.    else
  64.       Diagnostic("FindPreviousButton", EXIT, TRUE);
  65.    return pp;
  66.    }
  67.  
  68. void DisableButton(PushButton *Bptr)
  69.    {
  70.    Diagnostic("DisableButton", ENTER, TRUE);
  71.     if (Bptr && Bptr->Active && !Bptr->WidgetData->ParentControl) // Don't disable the button if it's part of another control.
  72.         {
  73.         GuiWindow *wptr = (GuiWindow *) Bptr->button.UserData;
  74.  
  75.         if (Bptr->hidden == 0)
  76.             DisableGadget(&Bptr->button, wptr->Win, TRUE);
  77.         else // The button is hidden
  78.             Bptr->button.Flags |= GFLG_DISABLED;
  79.        Bptr->Active = FALSE;
  80.        Diagnostic("DisableButton", EXIT, TRUE);
  81.         }
  82.     else
  83.        Diagnostic("DisableButton", EXIT, FALSE);
  84.    }
  85.  
  86. void DisableAllButtons(void)
  87.    {
  88.    PushButton *ggl = Gui.GGLfirst;
  89.    Diagnostic("DisableAllButtons", ENTER, TRUE);
  90.    while (ggl)
  91.       {
  92.       DisableButton(ggl);
  93.       ggl = ggl->Next;
  94.       }
  95.    Diagnostic("DisableAllButtons", EXIT, TRUE);
  96.    }
  97.  
  98. void DisableWinButtons(GuiWindow *w)
  99.    {
  100.    PushButton *g = Gui.GGLfirst;
  101.    Diagnostic("DisableWinButtons", ENTER, TRUE);
  102.    while (g)
  103.          {
  104.          if (g->button.UserData == (APTR) w)
  105.             DisableButton(g);
  106.       g = g->Next;
  107.          }
  108.    Diagnostic("DisableWinButtons", EXIT, TRUE);
  109.    }
  110.  
  111. void EnableButton(PushButton *Bptr)
  112.    {
  113.    Diagnostic("EnableButton", ENTER, TRUE);
  114.     if (Bptr && (!Bptr->Active) && !Bptr->WidgetData->ParentControl) // Don't enable the button if it's part of another control.
  115.         {
  116.         /* Only the border will be refreshed, leaving the rest of the button still looking shaded and
  117.             disabled.  Clear it here before refreshing. */
  118.         if (Bptr->hidden == 0)
  119.             {
  120.             GuiWindow *wptr = (GuiWindow *) Bptr->button.UserData;
  121.  
  122.             AreaColFill(wptr->Win->RPort, Bptr->button.LeftEdge, Bptr->button.TopEdge, Bptr->button.Width,
  123.                     Bptr->button.Height, GetBackCol(Bptr->WidgetData->Parent));
  124.             EnableGadget(&(Bptr->button), wptr->Win, TRUE);
  125.             }
  126.         else // The button is hidden
  127.             Bptr->button.Flags ^= GFLG_DISABLED;
  128.        Bptr->Active = TRUE;
  129.        Diagnostic("EnableButton", EXIT, TRUE);
  130.         }
  131.     else
  132.         Diagnostic("EnableButton", EXIT, FALSE);
  133.    }
  134.  
  135. void EnableAllButtons(void)
  136.    {
  137.    PushButton *ggl = Gui.GGLfirst;
  138.    Diagnostic("EnableAllButtons", ENTER, TRUE);
  139.    while (ggl)
  140.       {
  141.       EnableButton(ggl);
  142.       ggl = ggl->Next;
  143.       }
  144.    Diagnostic("EnableAllButtons", EXIT, TRUE);
  145.    }
  146.  
  147. void EnableWinButtons(GuiWindow *w)
  148.    {
  149.    PushButton *g = Gui.GGLfirst;
  150.    Diagnostic("EnableWinButtons", ENTER, TRUE);
  151.    while (g)
  152.          {
  153.       if (g->button.UserData == (APTR) w)
  154.             EnableButton(g);
  155.          g = g->Next;
  156.       }
  157.    Diagnostic("EnableWinButtons", EXIT, TRUE);
  158.    }
  159.  
  160. static void UndrawButton(PushButton *Bptr)
  161.     {
  162.     AreaColFill(((GuiWindow *)Bptr->button.UserData)->Win->RPort, Bptr->button.LeftEdge,
  163.             Bptr->button.TopEdge, Bptr->button.Width, Bptr->button.Height, GetBackCol(Bptr->WidgetData->Parent));
  164.     }
  165.  
  166. BOOL ShowButton(PushButton *Bptr)
  167.     {
  168.     Diagnostic("ShowButton", ENTER, TRUE);
  169.     if (Bptr)
  170.         {
  171.         BOOL InFrame = !ISGUIWINDOW(Bptr->WidgetData->Parent);
  172.         GuiWindow *Wptr = (GuiWindow *) Bptr->button.UserData;
  173.  
  174.         if (Bptr->hidden == 1) // The button is really hidden
  175.             if (InFrame && ((Frame *) Bptr->WidgetData->Parent)->hidden != 0)
  176.                 Bptr->hidden = -1; // The button is in a hidden frame so it remains hidden
  177.             else
  178.                 {
  179.                 Bptr->hidden = 0;
  180.                 AddGadget(Wptr->Win, &Bptr->button, -1);
  181.                 }
  182.         if (Bptr->hidden == 0)
  183.             {
  184.             GuiBitMap *gbm = Bptr->bitmap;
  185.  
  186.             if (!(Bptr->WidgetData->flags & BN_CLEAR))
  187.                 AreaColFill(Wptr->Win->RPort, Bptr->button.LeftEdge, Bptr->button.TopEdge,
  188.                         Bptr->button.Width, Bptr->button.Height, Bptr->light.BackPen);
  189.             RefreshGList(&Bptr->button, Wptr->Win, NULL, 1);
  190.             while (gbm)
  191.                 {
  192.                 // Refresh the bitmap instance
  193.                 gbm->bmi = ShowBitMap(gbm, Wptr, Bptr->button.LeftEdge + 1, Bptr->button.TopEdge + 1,
  194.                         gbm->flags);
  195.                 gbm = gbm->next;
  196.                 }
  197.             WaitBlit();
  198.             }
  199.         return Diagnostic("ShowButton", EXIT, TRUE);
  200.         }
  201.     return Diagnostic("ShowButton", EXIT, FALSE);
  202.     }
  203.  
  204. BOOL HideButton(PushButton *Bptr)
  205.     {
  206.     Diagnostic("HideButton", ENTER, TRUE);
  207.     if (Bptr)
  208.         {
  209.         if (Bptr->hidden == 0)
  210.             {
  211.             GuiBitMap *gbm = Bptr->bitmap;
  212.  
  213.             RemoveGadget(((GuiWindow *) Bptr->button.UserData)->Win, &(Bptr->button));
  214.             while (gbm)
  215.                 {
  216.                 if (gbm->bmi)
  217.                     {
  218.                     GuiFree(gbm->bmi);
  219.                     gbm->bmi = NULL;
  220.                     }
  221.                 gbm = gbm->next;
  222.                 }
  223.             UndrawButton(Bptr);
  224.             }
  225.         Bptr->hidden = 1;
  226.         return Diagnostic("HideButton", EXIT, TRUE);
  227.         }
  228.     return Diagnostic("HideButton", EXIT, FALSE);
  229.     }
  230.  
  231. void DestroyButton(PushButton *Bptr, BOOL refresh)
  232.    {
  233.    PushButton *pp, *cBptr = Bptr;
  234.    Diagnostic("DestroyButton", ENTER, TRUE);
  235.    pp = FindPreviousButton(&cBptr);
  236.    if (Bptr)
  237.       {
  238.         Frame *Child; // Could be any type of widget
  239.  
  240.         if (!Bptr->WidgetData->ParentControl) // Don't destroy the button if it's part of another control.
  241.             {
  242.             GuiBitMap *gbm = Bptr->bitmap;
  243.  
  244.             if (Bptr->hidden == 0)
  245.                 RemoveGadget(((GuiWindow *) Bptr->button.UserData)->Win, &(Bptr->button));
  246.           if (Bptr == Gui.GGLfirst)
  247.              Gui.GGLfirst = Bptr->Next;
  248.           else
  249.              pp->Next = Bptr->Next;
  250.             if (Bptr->ULfont)
  251.                 {
  252.                 GuiFree(Bptr->ULfont->ta_Name);
  253.                 GuiFree(Bptr->ULfont);
  254.                 }
  255.             if (Bptr->text1.ITextFont)
  256.                 {
  257.                 GuiFree(Bptr->text1.ITextFont->ta_Name);
  258.                 GuiFree(Bptr->text1.ITextFont);
  259.                 }
  260.             if (Bptr->t1)
  261.                 GuiFree(Bptr->t1);
  262.             if (Bptr->t3)
  263.                 GuiFree(Bptr->t3);
  264.             if (Bptr->WidgetData->os)
  265.                 GuiFree(Bptr->WidgetData->os);
  266.             if (Bptr->cbCopy)
  267.                 GuiFree(Bptr->cbCopy);
  268.             while (gbm)
  269.                 {
  270.                 GuiBitMap *ngbm = gbm->next;
  271.                 if (gbm->bmi)
  272.                     if (refresh)
  273.                         HideBitMap(gbm->bmi);
  274.                     else
  275.                         GuiFree(gbm->bmi);
  276.                 if (gbm->obm)
  277.                     FreeGuiBitMap(gbm->obm);
  278.                 FreeGuiBitMap(gbm);
  279.                 gbm = ngbm;
  280.                 }
  281.             Child = Bptr->WidgetData->ChildWidget;
  282.             while (Child)
  283.                 {
  284.                 void *next = Child->WidgetData->NextWidget;
  285.                 Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  286.                 Destroy(Child, refresh);
  287.                 Child = next;
  288.                 }
  289.             if (refresh && Bptr->hidden == 0)
  290.                 UndrawButton(Bptr);
  291.           GuiFree(Bptr->WidgetData);
  292.           GuiFree(Bptr);
  293.           }
  294.         }
  295.    else
  296.       {
  297.       SetLastErr("Attempt to destroy a non-existing button.");
  298.       Diagnostic("DestroyButton", EXIT, FALSE);
  299.       return;
  300.       }
  301.    Diagnostic("DestroyButton", EXIT, TRUE);
  302.    }
  303.  
  304. void DestroyAllButtons(BOOL refresh)
  305.    {
  306.    PushButton *g = Gui.GGLfirst, *next = NULL;
  307.    Diagnostic("DestroyAllButtons", ENTER, TRUE);
  308.    while (g)
  309.       {
  310.         next = g->Next;
  311.       DestroyButton(g, refresh);
  312.       g = next;
  313.       }
  314.    Diagnostic("DestroyAllButtons", EXIT, TRUE);
  315.    }
  316.  
  317. void DestroyWinButtons(GuiWindow *w, BOOL refresh)
  318.    {
  319.    PushButton *g = Gui.GGLfirst, *next = NULL;
  320.    BOOL message = FALSE;
  321.    Diagnostic("DestroyWinButtons", ENTER, TRUE);
  322.    while (g)
  323.       {
  324.         next = g->Next;
  325.       if (g->button.UserData == (APTR) w)
  326.          {
  327.          DestroyButton(g, refresh);
  328.          message = TRUE;
  329.          }
  330.         g = next;
  331.       }
  332.    if (Gui.CleanupFlag && message)
  333.       SetLastErr("Window closed before all of its buttons were destroyed.");
  334.    Diagnostic("DestroyWinButtons", EXIT, TRUE);
  335.    }
  336.  
  337. void ResizeButton(PushButton *Bptr, int x, int y, int width, int height, BOOL eraseold)
  338.     {
  339.     int len1 = 0, len2, len3 = 0, MaxLen;
  340.  
  341.     /*    If the button is in a coloured frame then no need to blank it because the parent frame will
  342.         blank it's entire contents. */
  343.     if (eraseold && GetBackCol(Bptr->WidgetData->Parent) == GUIWIN(Bptr)->Win->RPort->BgPen)
  344.         UndrawButton(Bptr);
  345.  
  346.     // The button size is dependant on the caption and the font.  Since the caption and font are not changing, nor is the size!
  347.     if (Bptr->WidgetData->flags & S_FONT_SENSITIVE)
  348.         {
  349.         width = Bptr->button.Width;
  350.         height = Bptr->button.Height;
  351.         }
  352.  
  353.     Bptr->button.LeftEdge = x;
  354.     Bptr->button.Width = width;
  355.     Bptr->button.TopEdge = y;
  356.     Bptr->button.Height = height;
  357.  
  358.     /* Outer border (two structures) */
  359.     /* White */
  360.     Bptr->points[0] = Bptr->points[2] = Bptr->points[3] = Bptr->points[5] = 0;
  361.     Bptr->points[1] = height - 1;
  362.     Bptr->points[4] = width - 2;
  363.     /* Black */
  364.     Bptr->points[6] = 1;
  365.     Bptr->points[11] = 0;
  366.     Bptr->points[7] = Bptr->points[9] = height - 1;
  367.     Bptr->points[8] = Bptr->points[10] = width - 1;
  368.  
  369.     Bptr->text1.TopEdge = ((height - ((GuiWindow *)Bptr->button.UserData)->Win->RPort->TxHeight) / 2) + 1;
  370.     Bptr->text2.TopEdge = Bptr->text3.TopEdge = Bptr->text1.TopEdge;
  371.  
  372.     MaxLen = width - 2;
  373.  
  374.     if (Bptr->t1)
  375.         {
  376.         UnTruncateIText(&Bptr->text1, Bptr->t1);
  377.         len1 = IntuiTextLength(&Bptr->text1);
  378.  
  379.         if (Bptr->t2[0])
  380.             Bptr->text1.NextText = &Bptr->text2; // Reset incase text2 has previously been truncated off.
  381.         }
  382.     len2 = (Bptr->t2[0] ? IntuiTextLength(&(Bptr->text2)) : 0);
  383.     if (Bptr->t3)
  384.         {
  385.         UnTruncateIText(&Bptr->text3, Bptr->t3);
  386.         len3 = IntuiTextLength(&Bptr->text3);
  387.         }
  388.  
  389.     if (len3)
  390.         {
  391.         TruncateIText(&Bptr->text3, Bptr->t3, MaxLen - len2 - len1, JUSTIFY_LEFT);
  392.         len3 = IntuiTextLength(&Bptr->text3);
  393.         }
  394.     if (len2)
  395.         if (len1 + len2 > MaxLen)
  396.             {
  397.             Bptr->text1.NextText = NULL;
  398.             len2 = 0;
  399.             }
  400.     if (len1)
  401.         {
  402.         TruncateIText(&Bptr->text1, Bptr->t1, MaxLen, JUSTIFY_LEFT);
  403.         len1 = IntuiTextLength(&Bptr->text1);
  404.         }
  405.  
  406.     Bptr->text1.LeftEdge  = (width - (len1 + len2 + len3)) / 2;
  407.     Bptr->text2.LeftEdge = Bptr->text1.LeftEdge + len1;
  408.     Bptr->text3.LeftEdge = Bptr->text2.LeftEdge + len2;
  409.  
  410.     Bptr->WidgetData->left = x;
  411.     Bptr->WidgetData->top = y;
  412.     Bptr->WidgetData->width = width;
  413.     Bptr->WidgetData->height = height;
  414.     }
  415.  
  416. EXTC PushButton* FOXLIB MakeButton(REGA0 void *Parent, REGA1 char *name, REGD0 int left, REGD1 int top, REGD2 int
  417.    width, REGD3 int height, REGD4 int key, REGA2 struct Border *cb, REGA3 int
  418.    (* __far __stdargs callfn) (PushButton*), REGD5 short flags, REGD6 void *extension)
  419.    {
  420.     GuiWindow *Wptr;
  421.     int realleft, realtop;
  422.    PushButton *Bptr;
  423.     Frame *ParentFrame = NULL;
  424.  
  425.    Diagnostic("MakeButton", ENTER, TRUE);
  426.  
  427.     if (!Parent)
  428.         {
  429.         Diagnostic("MakeButton", EXIT, FALSE);
  430.         return NULL;
  431.         }
  432.    if ((Bptr = (PushButton *) GuiMalloc(sizeof(PushButton), 0)) == NULL)
  433.         {
  434.         Diagnostic("MakeButton", EXIT, FALSE);
  435.         return NULL;
  436.         }
  437.    if ((Bptr->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), 0)) == NULL)
  438.         {
  439.         GuiFree(Bptr);
  440.         Diagnostic("MakeButton", EXIT, FALSE);
  441.         return NULL;
  442.         }
  443.     if (cb)
  444.         {
  445.         int l;
  446.         if ((Bptr->cbCopy = (short *) GuiMalloc(cb->Count * 2 * sizeof(short), 0)) == NULL)
  447.             {
  448.             GuiFree(Bptr->WidgetData);
  449.             GuiFree(Bptr);
  450.             Diagnostic("MakeButton", EXIT, FALSE);
  451.             return NULL;
  452.             }
  453.         for (l = 0; l < 2 * cb->Count; l++)
  454.             Bptr->cbCopy[l] = cb->XY[l];
  455.         }
  456.     else
  457.         Bptr->cbCopy = NULL;
  458.  
  459.     if (flags & S_FONT_SENSITIVE)
  460.         {
  461.         width = GuiTextLength(name, &GuiFont) - (strchr(name, '_') ? GuiTextLength("_", &GuiFont) : 0) + 8;
  462.         height = GuiFont.ta_YSize + 8;
  463.         }
  464.  
  465.     if (!ISGUIWINDOW(Parent))
  466.         {
  467.         ParentFrame = (Frame *) Parent;
  468.         realleft = left + ParentFrame->button.LeftEdge;
  469.         if (left < 0)
  470.             realleft += ParentFrame->points[8] + 1;
  471.         realtop = top + ParentFrame->button.TopEdge;
  472.         if (top < 0)
  473.             realtop += ParentFrame->points[1] + 1;
  474.         Wptr = (GuiWindow *) ParentFrame->button.UserData;
  475.         }
  476.     else
  477.         {
  478.         Wptr = (GuiWindow *) Parent;
  479.         realleft = (left < 0 ? Wptr->Win->Width + left : left);
  480.         realtop = (top < 0 ? Wptr->Win->Height + top : top);
  481.         }
  482.  
  483.     Bptr->WidgetData->ObjectType = ButtonObject;
  484.     Bptr->WidgetData->Parent = Parent;
  485.     Bptr->WidgetData->NextWidget = NULL;
  486.     Bptr->WidgetData->ChildWidget = NULL;
  487.  
  488.     if (flags & SYS_BN_HIDDEN)
  489.         {
  490.         Bptr->hidden = 1;
  491.         flags &= ~SYS_BN_HIDDEN;
  492.         }
  493.     else if (ParentFrame && ParentFrame->hidden != 0)
  494.         Bptr->hidden = -1;
  495.     else
  496.         Bptr->hidden = 0;
  497.     if (ParentFrame && (flags & S_AUTO_SIZE) && !(ParentFrame->WidgetData->flags & S_AUTO_SIZE))
  498.         flags ^= S_AUTO_SIZE;
  499.     if (flags & S_AUTO_SIZE)
  500.         {
  501.         if (!(Bptr->WidgetData->os = (OriginalSize *) GuiMalloc(sizeof(OriginalSize), 0)))
  502.             {
  503.             if (Bptr->cbCopy)
  504.                 GuiFree(Bptr->cbCopy);
  505.             GuiFree(Bptr->WidgetData);
  506.             GuiFree(Bptr);
  507.           Diagnostic("MakeButton", EXIT, FALSE);
  508.           return NULL;
  509.           }
  510.         Bptr->WidgetData->os->left = realleft;
  511.         Bptr->WidgetData->os->top = realtop;
  512.         Bptr->WidgetData->os->width = width;
  513.         Bptr->WidgetData->os->height = height;
  514.         }
  515.     else
  516.         Bptr->WidgetData->os = NULL;
  517.  
  518.     Bptr->WidgetData->flags = flags;
  519.     Bptr->t2[0] = Bptr->t2[1] = 0;
  520.     Bptr->t1 = Bptr->t3 = NULL;
  521.     Bptr->ULfont = CopyFont(&GuiULFont);
  522.  
  523.     if (name && strlen(name))
  524.         {
  525.         char *us = strchr(name, '_');
  526.         if (us && us[1] == 0) // If the user is stupid enough to pass _ as the last character then ignore it.
  527.             us = NULL;
  528.         if (us)
  529.             // Replace the underscore (us) with NULL to find the length of the first string.
  530.             *us = 0;
  531.  
  532.         if (us != name) // If the underscore is not the first character
  533.             if (Bptr->t1 = (char *) GuiMalloc((strlen(name) + 2) * sizeof(char), 0))
  534.                 {
  535.                 Bptr->t1[0] = 0;
  536.                 strcpy(&Bptr->t1[1], name);
  537.                 }
  538.             else
  539.                 {
  540.                 if (us)
  541.                     *us = '_';
  542.                 GuiFree(Bptr->WidgetData->os);
  543.                 if (Bptr->cbCopy)
  544.                     GuiFree(Bptr->cbCopy);
  545.                 GuiFree(Bptr->WidgetData);
  546.                  GuiFree(Bptr);
  547.                  Diagnostic("MakeButton", EXIT, FALSE);
  548.               return NULL;
  549.                 }
  550.  
  551.         if (us)
  552.             {
  553.             *us = '_';
  554.             Bptr->t2[0] = us[1];
  555.             if (us[2])
  556.                 {
  557.                 if (Bptr->t3 = (char *) GuiMalloc((strlen(&us[2]) + 2) * sizeof(char), 0))
  558.                     {
  559.                     Bptr->t3[0] = 0;
  560.                     strcpy(&Bptr->t3[1], &us[2]);
  561.                     }
  562.                 else
  563.                     {
  564.                     if (Bptr->t1)
  565.                         GuiFree(Bptr->t1);
  566.                   GuiFree(Bptr->WidgetData->os);
  567.                     if (Bptr->cbCopy)
  568.                         GuiFree(Bptr->cbCopy);
  569.                     GuiFree(Bptr->WidgetData);
  570.                   GuiFree(Bptr);
  571.                   Diagnostic("MakeButton", EXIT, FALSE);
  572.                   return NULL;
  573.                     }
  574.                 }
  575.             }
  576.         }
  577.  
  578.     Bptr->light.Count = Bptr->dark.Count = Bptr->sdark.Count = Bptr->slight.Count = 3;
  579.     Bptr->dark.XY = Bptr->sdark.XY = &(Bptr->points[6]);
  580.     Bptr->light.XY = Bptr->slight.XY = Bptr->points;
  581.    Bptr->light.LeftEdge   = Bptr->light.TopEdge = 0;
  582.    Bptr->light.NextBorder = &(Bptr->dark);
  583.    Bptr->light.FrontPen   = Gui.HiPen;
  584.     Bptr->light.BackPen    = Gui.BackCol; // Ignored by intuition - just used for storage.
  585.    Bptr->light.DrawMode   = JAM1;
  586.    Bptr->dark.LeftEdge    = Bptr->dark.TopEdge = 0;
  587.    Bptr->dark.NextBorder  = cb;
  588.    Bptr->dark.FrontPen    = Gui.LoPen;
  589.    Bptr->dark.DrawMode    = JAM1;
  590.  
  591.    Bptr->slight.LeftEdge   = Bptr->slight.TopEdge = 0;
  592.    Bptr->slight.NextBorder = &(Bptr->sdark);
  593.     Bptr->slight.FrontPen   = Gui.LoPen;
  594.    Bptr->slight.DrawMode   = JAM1;
  595.    Bptr->sdark.LeftEdge    = Bptr->sdark.TopEdge = 0;
  596.    Bptr->sdark.NextBorder  = cb;
  597.    Bptr->sdark.FrontPen    = Gui.HiPen;
  598.    Bptr->sdark.DrawMode    = JAM1;
  599.  
  600.    Bptr->button.NextGadget = NULL;
  601.     Bptr->button.Flags      = GFLG_GADGHIMAGE;
  602.    Bptr->button.Activation = RELVERIFY;
  603.     if (flags & BN_AR)
  604.       Bptr->button.Activation |= GADGIMMEDIATE;
  605.    Bptr->button.GadgetType   = BOOLGADGET;
  606.    Bptr->button.GadgetRender = (APTR) &(Bptr->light);
  607.     Bptr->button.SelectRender = (APTR) &(Bptr->slight);
  608.     if (name && strlen(name))
  609.         {
  610.         Bptr->button.GadgetText = (Bptr->t1 ? &(Bptr->text1) : &(Bptr->text2));
  611.         /*    The Parent screen's font is the font that would be used by default if we set this to NULL but
  612.             then IntuiTextLength might return incorrect values because it doesn't know which screen we're
  613.             going to draw the text in!  To be on the safe side, set this explicitly. */
  614.         Bptr->text1.ITextFont = CopyFont(&GuiFont);
  615.         Bptr->text3.ITextFont = Bptr->text1.ITextFont;
  616.         if (Bptr->t2[0])
  617.             {
  618. #ifdef OLD
  619.             Bptr->text2.ITextFont = NULL;
  620.             if (Wptr->WidgetData->Parent->Font == &GuiFont)
  621. #endif
  622.                 Bptr->text2.ITextFont = Bptr->ULfont;
  623. #ifdef OLD
  624.             else
  625.                 {
  626.                 /*    Just because it's not pointing to GuiFont, doesn't mean it's not the same font!  Let's
  627.                     check. */
  628.                 if (Wptr->WidgetData->Parent->Font)
  629.                     if (Wptr->WidgetData->Parent->Font->ta_YSize == GuiFont.ta_YSize &&
  630.                             Wptr->WidgetData->Parent->Font->ta_Style == GuiFont.ta_Style &&
  631.                             Wptr->WidgetData->Parent->Font->ta_Flags == GuiFont.ta_Flags &&
  632.                             strcmp(Wptr->WidgetData->Parent->Font->ta_Name, GuiFont.ta_Name) == 0)
  633.                         // It's the same font!
  634.                         Bptr->text2.ITextFont = &GuiULFont;
  635.                 if (Wptr->WidgetData->Parent->Font && !Bptr->text2.ITextFont)
  636.                     // Make a copy of the font and add underline
  637.                     if (Bptr->ULfont = (struct TextAttr *) GuiMalloc(sizeof(struct TextAttr), 0))
  638.                         {
  639.                         memcpy(Bptr->ULfont, Wptr->WidgetData->Parent->Font, sizeof(struct TextAttr));
  640.                         /*    Now allocate and copy the name seperately because if we just point to the name
  641.                             in the screen font, we might lose it if the user changes it! */
  642.                         if (Bptr->ULfont->ta_Name = (char*) GuiMalloc((strlen(Wptr->WidgetData->Parent->Font->ta_Name) + 1) *
  643.                                 sizeof(char), 0))
  644.                             {
  645.                             strcpy(Bptr->ULfont->ta_Name, Wptr->WidgetData->Parent->Font->ta_Name);
  646.                             Bptr->ULfont->ta_Style |= FSF_UNDERLINED;
  647.                             Bptr->text2.ITextFont = Bptr->ULfont;
  648.                             }
  649.                         else
  650.                             {
  651.                             GuiFree(Bptr->ULfont);
  652.                             Bptr->ULfont = NULL;
  653.                             }
  654.                         }
  655.                 if (!Bptr->text2.ITextFont)
  656.                     // Well, it's not right but we have to use a font so we'd best use this one.
  657.                     {
  658.                     Bptr->text2.ITextFont = &GuiULFont;
  659.                     SetLastErr("Failed to find correct underlined font.  Default used.");
  660.                     }
  661.                 }
  662. #endif
  663.             }
  664.        Bptr->text1.FrontPen  = Bptr->text2.FrontPen = Bptr->text3.FrontPen = Gui.TextCol;
  665.        Bptr->text1.DrawMode  = Bptr->text2.DrawMode = Bptr->text3.DrawMode = JAM1;
  666.        Bptr->text1.IText = Bptr->t1 ? &Bptr->t1[1] : NULL;
  667.        Bptr->text2.IText = Bptr->t2;
  668.        Bptr->text3.IText = Bptr->t3 ? &Bptr->t3[1] : NULL;
  669.        Bptr->text1.NextText = (Bptr->t2[0] ? &(Bptr->text2) : NULL);
  670.        Bptr->text2.NextText = (Bptr->t3 ? &(Bptr->text3) : NULL);
  671.        Bptr->text3.NextText = NULL;
  672.         }
  673.     else
  674.         {
  675.         Bptr->button.GadgetText = NULL;
  676.         Bptr->text1.ITextFont = NULL;
  677.         }
  678.    Bptr->button.GadgetID = 0;
  679.    Bptr->button.UserData = (APTR) Wptr;
  680.  
  681.     // Set the width and height before calling resize because if the button is font sensitive, resize won't change teh width and height.
  682.     Bptr->button.Width = width;
  683.     Bptr->button.Height = height;
  684.     ResizeButton(Bptr, realleft, realtop, width, height, FALSE);
  685.  
  686.    Bptr->Callfn = callfn;
  687.    Bptr->Active = Bptr->OldStatus = TRUE;
  688.    Bptr->Key1 = key;
  689.    if (isupper(key))
  690.       Bptr->Key2 = tolower(key);
  691.    else if (islower(key))
  692.       Bptr->Key2 = toupper(key);
  693.    else
  694.       {
  695.       switch (key)
  696.          {
  697.          case  ',' : Bptr->Key2 =  '<'; break;
  698.          case  '<' : Bptr->Key2 =  ','; break;
  699.          case  '.' : Bptr->Key2 =  '>'; break;
  700.          case  '>' : Bptr->Key2 =  '.'; break;
  701.          case  '/' : Bptr->Key2 =  '?'; break;
  702.          case  '?' : Bptr->Key2 =  '/'; break;
  703.          case  ';' : Bptr->Key2 =  ':'; break;
  704.          case  ':' : Bptr->Key2 =  ';'; break;
  705.          case  '@' : Bptr->Key2 =  '#'; break;
  706.          case  '#' : Bptr->Key2 =  '@'; break;
  707.          case  '[' : Bptr->Key2 =  '{'; break;
  708.          case  '{' : Bptr->Key2 =  '['; break;
  709.          case  '}' : Bptr->Key2 =  ']'; break;
  710.          case  ']' : Bptr->Key2 =  '}'; break;
  711.          case '\\' : Bptr->Key2 =  '|'; break;
  712.          case  '|' : Bptr->Key2 = '\\'; break;
  713.          case  '=' : Bptr->Key2 =  '+'; break;
  714.          case  '+' : Bptr->Key2 =  '='; break;
  715.          case  '_' : Bptr->Key2 =  '-'; break;
  716.          case  '-' : Bptr->Key2 =  '_'; break;
  717.          case  '1' : Bptr->Key2 =  '!'; break;
  718.          case  '!' : Bptr->Key2 =  '1'; break;
  719.          case '\"' : Bptr->Key2 =  '2'; break;
  720.          case  '2' : Bptr->Key2 = '\"'; break;
  721.          case  '3' : Bptr->Key2 =  '£'; break;
  722.          case  '£' : Bptr->Key2 =  '3'; break;
  723.          case  '$' : Bptr->Key2 =  '4'; break;
  724.          case  '4' : Bptr->Key2 =  '$'; break;
  725.          case  '5' : Bptr->Key2 =  '%'; break;
  726.          case  '%' : Bptr->Key2 =  '5'; break;
  727.          case  '^' : Bptr->Key2 =  '6'; break;
  728.          case  '6' : Bptr->Key2 =  '^'; break;
  729.          case  '7' : Bptr->Key2 =  '&'; break;
  730.          case  '&' : Bptr->Key2 =  '7'; break;
  731.          case  '*' : Bptr->Key2 =  '8'; break;
  732.          case  '8' : Bptr->Key2 =  '*'; break;
  733.          case  '9' : Bptr->Key2 =  '('; break;
  734.          case  '(' : Bptr->Key2 =  '9'; break;
  735.          case  ')' : Bptr->Key2 =  '0'; break;
  736.          case  '0' : Bptr->Key2 =  ')'; break;
  737.          case '\'' : Bptr->Key2 =  '~'; break;
  738.          case  '~' : Bptr->Key2 = '\''; break;
  739.          default   : Bptr->Key2 =    0; break;
  740.          }
  741.       }
  742.     Bptr->WidgetData->ParentControl = NULL;
  743.     Bptr->Filefn = NULL;
  744.     Bptr->bitmap = NULL;
  745.    Bptr->Next = Gui.GGLfirst;
  746.    Gui.GGLfirst = Bptr;
  747.     if (Bptr->hidden == 0)
  748.         {
  749.         if (!(flags & BN_CLEAR))
  750.             AreaColFill(Wptr->Win->RPort, realleft, realtop, width, height, Gui.BackCol);
  751.         AddGadget(Wptr->Win, &(Bptr->button), -1);
  752.         RefreshGadgets(&(Bptr->button), Wptr->Win, NULL);
  753.         }
  754.    Diagnostic("MakeButton", EXIT, TRUE);
  755.    return Bptr;
  756.    }
  757.  
  758. PushButton *MakeFileButton(GuiWindow *Wptr, char *name, int left, int top, int width, int height, int key, struct Border *cb, int (*callfn) (char*, char*))
  759.     {
  760.     PushButton *FileButton = MakeButton(Wptr, name, left, top, width, height, key, cb, NULL, BN_CLEAR | BN_STD | S_AUTO_SIZE, NULL);
  761.     if (!FileButton)
  762.         return NULL;
  763.     FileButton->Filefn = callfn;
  764.     return FileButton;
  765.     }
  766.  
  767. typedef enum {SHOW, HIDE, DESTROY} Action;
  768.  
  769. static void EveryControl(Frame *f, Action action, BOOL refresh)
  770.     {
  771.     EditBox *e = Gui.FirstEditBox, *en;
  772.     OutputBox *o = Gui.FirstOutputBox, *on;
  773.     ListBox *l = Gui.FirstListBox, *ln;
  774.     PushButton *b = Gui.GGLfirst, *bn;
  775.     ProgressBar *p = Gui.FirstProgressBar, *pn;
  776.     TickBox *t = Gui.FirstTickBox, *tn;
  777.     RadioButton *r = Gui.FirstRadioButton, *rn;
  778.     Frame *fr = Gui.FirstFrame, *fn;
  779.  
  780.     Diagnostic("EveryControl", ENTER, TRUE);
  781.  
  782.     while (e)
  783.         {
  784.         en = e->next;
  785.         if ((Frame *) e->WidgetData->Parent == f)
  786.             if (e->list)
  787.                 {
  788.                 if (action == DESTROY)
  789.                     {
  790.                     /*    Destroying a drop-down list box may cause child dd list boxes to be destroyed so
  791.                         after calling DestroyDDListBox() we can't guarantee that en is still valid. */
  792.                     DestroyDDListBox(e, refresh);
  793.                     en = Gui.FirstEditBox;
  794.                     }
  795.                 else if (action == SHOW && e->hidden == -1)
  796.                     {
  797.                     e->hidden = 1; // Pretend it's really hidden so that the Show function will work
  798.                     ShowDDListBox(e);
  799.                     }
  800.                 else if (action == HIDE && e->hidden == 0)
  801.                     {
  802.                     HideDDListBox(e);
  803.                     e->hidden = -1;
  804.                     }
  805.                 }
  806.             else
  807.                 {
  808.                 if (action == DESTROY)
  809.                     DestroyEditBox(e, refresh);
  810.                 else if (action == SHOW && e->hidden == -1)
  811.                     {
  812.                     e->hidden = 1; // Pretend it's really hidden so that the Show function will work
  813.                     ShowEditBox(e);
  814.                     }
  815.                 else if (action == HIDE && e->hidden == 0)
  816.                     {
  817.                     HideEditBox(e);
  818.                     e->hidden = -1;
  819.                     }
  820.                 }
  821.         e = en;
  822.         }
  823.     while (o)
  824.         {
  825.         on = o->next;
  826.         if ((Frame *) o->WidgetData->Parent == f)
  827.             {
  828.             if (action == DESTROY)
  829.                 DestroyOutputBox(o, refresh);
  830.             else if (action == SHOW && o->hidden == -1)
  831.                 {
  832.                 o->hidden = 1; // Pretend it's really hidden so that the Show function will work
  833.                 ShowOutputBox(o);
  834.                 }
  835.             else if (action == HIDE && o->hidden == 0)
  836.                 {
  837.                 HideOutputBox(o);
  838.                 o->hidden = -1;
  839.                 }
  840.             }
  841.         o = on;
  842.         }
  843.     while (l)
  844.         {
  845.         ln = l->NextListBox;
  846.         if ((Frame *) l->WidgetData->Parent == f)
  847.             {
  848.             if (action == DESTROY)
  849.                 DestroyListBox(l, refresh);
  850.             else if (action == SHOW && l->hidden == -1)
  851.                 {
  852.                 l->hidden = 1; // Pretend it's really hidden so that the Show function will work
  853.                 ShowListBox(l);
  854.                 }
  855.             else if (action == HIDE && l->hidden == 0)
  856.                 {
  857.                 HideListBox(l);
  858.                 l->hidden = -1;
  859.                 }
  860.             }
  861.         l = ln;
  862.         }
  863.     while (p)
  864.         {
  865.         pn = p->Next;
  866.         if ((Frame *) p->WidgetData->Parent == f)
  867.             {
  868.             if (action == DESTROY)
  869.                 DestroyProgressBar(p, refresh);
  870.             else if (action == SHOW && p->hidden == -1)
  871.                 {
  872.                 p->hidden = 1; // Pretend it's really hidden so that the Show function will work
  873.                 ShowProgressBar(p);
  874.                 }
  875.             else if (action == HIDE && p->hidden == 0)
  876.                 {
  877.                 HideProgressBar(p);
  878.                 p->hidden = -1;
  879.                 }
  880.             }
  881.         p = pn;
  882.         }
  883.     while (t)
  884.         {
  885.         tn = t->Next;
  886.         if ((Frame *) t->WidgetData->Parent == f)
  887.             {
  888.             if (action == DESTROY)
  889.                 DestroyTickBox(t, refresh);
  890.             else if (action == SHOW && t->hidden == -1)
  891.                 {
  892.                 t->hidden = 1; // Pretend it's really hidden so that the Show function will work
  893.                 ShowTickBox(t);
  894.                 }
  895.             else if (action == HIDE && t->hidden == 0)
  896.                 {
  897.                 HideTickBox(t);
  898.                 t->hidden = -1;
  899.                 }
  900.             }
  901.         t = tn;
  902.         }
  903.     while (r)
  904.         {
  905.         rn = r->Next;
  906.         if ((Frame *) r->WidgetData->Parent == f)
  907.             {
  908.             if (action == DESTROY)
  909.                 DestroyRadioButton(r, refresh);
  910.             else if (action == SHOW && r->hidden == -1)
  911.                 {
  912.                 r->hidden = 1; // Pretend it's really hidden so that the Show function will work
  913.                 ShowRadioButton(r);
  914.                 }
  915.             else if (action == HIDE && r->hidden == 0)
  916.                 {
  917.                 HideRadioButton(r);
  918.                 r->hidden = -1;
  919.                 }
  920.             }
  921.         r = rn;
  922.         }
  923.     while (b)
  924.         {
  925.         bn = b->Next;
  926.         if ((Frame *) b->WidgetData->Parent == f)
  927.             {
  928.             if (action == DESTROY)
  929.                 DestroyButton(b, refresh);
  930.             else if (action == SHOW && b->hidden == -1)
  931.                 {
  932.                 b->hidden = 1; // Pretend it's really hidden so that the Show function will work
  933.                 ShowButton(b);
  934.                 }
  935.             else if (action == HIDE && b->hidden == 0)
  936.                 {
  937.                 HideButton(b);
  938.                 b->hidden = -1;
  939.                 }
  940.             }
  941.         b = bn;
  942.         }
  943.     while (fr)
  944.         {
  945.         fn = fr->next;
  946.         if ((Frame *) fr->WidgetData->Parent == f)
  947.             {
  948.             // Recursion here we come!
  949.             if (action == DESTROY)
  950.                 {
  951.                 /* Destroying a frame will cause any frames within it to be destroyed so, after destroying
  952.                     a frame, we can't guarantee that fn is still valid. */
  953.                 DestroyFrame(fr, refresh);
  954.                 fn = Gui.FirstFrame;
  955.                 }
  956.             else if (action == SHOW && fr->hidden == -1)
  957.                 {
  958.                 fr->hidden = 1; // Pretend it's really hidden so that the Show function will work
  959.                 ShowFrame(fr);
  960.                 }
  961.             else if (action == HIDE && fr->hidden == 0)
  962.                 {
  963.                 HideFrame(fr);
  964.                 fr->hidden = -1;
  965.                 }
  966.             }
  967.         fr = fn;
  968.         }
  969.     Diagnostic("EveryControl", EXIT, TRUE);
  970.     }
  971.  
  972. static Frame *FindPreviousFrame(Frame **Fptr)
  973.    {
  974.    BOOL Found = FALSE;
  975.    Frame *p = Gui.FirstFrame, *pp = NULL;
  976.    Diagnostic("FindPreviousFrame", ENTER, TRUE);
  977.    while(p)
  978.       {
  979.       if (p == *Fptr)
  980.          {
  981.          Found = TRUE;
  982.          break;
  983.          }
  984.       else
  985.          {
  986.          pp = p;
  987.          p = p->next;
  988.          }
  989.       }
  990.    if (!Found)
  991.       {
  992.       *Fptr = p = pp = NULL;
  993.       Diagnostic("FindPreviousFrame", EXIT, FALSE);
  994.       }
  995.    else
  996.       Diagnostic("FindPreviousFrame", EXIT, TRUE);
  997.    return pp;
  998.    }
  999.  
  1000. BOOL ShowFrame(Frame *Fptr)
  1001.     {
  1002.     if (!Fptr)
  1003.         return FALSE;
  1004.     else
  1005.         if (Fptr->hidden == 1) // The frame is really hidden
  1006.             if ((!ISGUIWINDOW(Fptr->WidgetData->Parent)) && ((Frame *) Fptr->WidgetData->Parent)->hidden != 0)
  1007.                 Fptr->hidden = -1; // The frame is in a hidden frame so it will remain hidden
  1008.             else
  1009.                 {
  1010.                 GuiBitMap *gbm = Fptr->bitmap;
  1011.  
  1012.                 // Refresh the background.
  1013.                 if (!(Fptr->WidgetData->flags & FM_CLEAR))
  1014.                     AreaColFill(((GuiWindow *) Fptr->button.UserData)->Win->RPort, Fptr->button.LeftEdge,
  1015.                             Fptr->button.TopEdge, Fptr->points[8] + 1, Fptr->points[1] + 1, Fptr->light.BackPen);
  1016.                 AddGadget(((GuiWindow *) Fptr->button.UserData)->Win, &(Fptr->button), -1);
  1017.                 RefreshGadgets(&(Fptr->button), ((GuiWindow *) Fptr->button.UserData)->Win, NULL);
  1018.                 while (gbm)
  1019.                     {
  1020.                     // Refresh the bitmap instance
  1021.                     gbm->bmi = ShowBitMap(gbm, (GuiWindow *) Fptr->button.UserData, Fptr->button.LeftEdge + 1,
  1022.                             Fptr->button.TopEdge + 1, gbm->flags);
  1023.                     gbm = gbm->next;
  1024.                     }
  1025.                 WaitBlit();
  1026.                 Fptr->hidden = 0;
  1027.                 EveryControl(Fptr, SHOW, TRUE);
  1028.                 }
  1029.     return TRUE;
  1030.     }
  1031.  
  1032. static void UndrawFrame(Frame *Fptr)
  1033.     {
  1034.     int width;
  1035.  
  1036.     if ((Fptr->WidgetData->flags & SYS_FM_ROUNDED) && Fptr->points[1] + 1 >= 6 && !(Fptr->WidgetData->flags & FM_BORDERLESS)) // Rounded corners
  1037.         width = Fptr->points[24];
  1038.     else
  1039.         width = Fptr->points[8];
  1040.  
  1041.     AreaColFill(((GuiWindow *) Fptr->button.UserData)->Win->RPort, Fptr->button.LeftEdge,
  1042.             Fptr->button.TopEdge, width + 1, Fptr->points[1] + 1, GetBackCol(Fptr->WidgetData->Parent));
  1043.     }
  1044.  
  1045. BOOL HideFrame(Frame *Fptr)
  1046.     {
  1047.     if (!Fptr)
  1048.         return FALSE;
  1049.     else
  1050.         {
  1051.         if (Fptr->hidden == 0)
  1052.             {
  1053.             GuiBitMap *gbm = Fptr->bitmap;
  1054.  
  1055.             RemoveGadget(((GuiWindow *) Fptr->button.UserData)->Win, &(Fptr->button));
  1056.             while (gbm)
  1057.                 {
  1058.                 if (gbm->bmi)
  1059.                     {
  1060.                     GuiFree(gbm->bmi);
  1061.                     gbm->bmi = NULL;
  1062.                     }
  1063.                 gbm = gbm->next;
  1064.                 }
  1065.             UndrawFrame(Fptr);
  1066.             EveryControl(Fptr, HIDE, TRUE);
  1067.             }
  1068.         Fptr->hidden = 1;
  1069.         }
  1070.     return TRUE;
  1071.     }
  1072.  
  1073. void DestroyFrame(Frame *Fptr, BOOL refresh)
  1074.    {
  1075.    Diagnostic("DestroyFrame", ENTER, TRUE);
  1076.    if (Fptr)
  1077.       {
  1078.         Frame *Child; // Could be any type of widget
  1079.         if (Fptr->WidgetData->ParentControl == NULL)
  1080.             {
  1081.             Frame *cFptr = Fptr, *pp = FindPreviousFrame(&cFptr);
  1082.             GuiBitMap *gbm = Fptr->bitmap;
  1083.  
  1084.             EveryControl(Fptr, DESTROY, refresh);
  1085.             if (Fptr->hidden == 0)
  1086.               RemoveGadget(((GuiWindow *) Fptr->button.UserData)->Win, &(Fptr->button));
  1087.              if (Fptr == Gui.FirstFrame)
  1088.                 Gui.FirstFrame = Fptr->next;
  1089.           else
  1090.                 pp->next = Fptr->next;
  1091.             if (Fptr->t)
  1092.                 GuiFree(Fptr->t);
  1093.             while (gbm)
  1094.                 {
  1095.                 GuiBitMap *ngbm = gbm->next;
  1096.                 if (gbm->bmi)
  1097.                     if (refresh)
  1098.                         HideBitMap(gbm->bmi);
  1099.                     else
  1100.                         GuiFree(gbm->bmi);
  1101.                 if (gbm->obm)
  1102.                     FreeGuiBitMap(gbm->obm);
  1103.                 FreeGuiBitMap(gbm);
  1104.                 gbm = ngbm;
  1105.                 }
  1106.             if (refresh && Fptr->hidden == 0)
  1107.                 UndrawFrame(Fptr);
  1108.             if (Fptr->WidgetData->os)
  1109.                 GuiFree(Fptr->WidgetData->os);
  1110.             if (Fptr->cbCopy)
  1111.                 GuiFree(Fptr->cbCopy);
  1112.             if (Fptr->text.ITextFont)
  1113.                 {
  1114.                 if (Fptr->text.ITextFont->ta_Name)
  1115.                     GuiFree(Fptr->text.ITextFont->ta_Name);
  1116.                 GuiFree(Fptr->text.ITextFont);
  1117.                 }
  1118.             Child = Fptr->WidgetData->ChildWidget;
  1119.             while (Child)
  1120.                 {
  1121.                 void *next = Child->WidgetData->NextWidget;
  1122.                 Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  1123.                 Destroy(Child, refresh);
  1124.                 Child = next;
  1125.                 }
  1126.           GuiFree(Fptr->WidgetData);
  1127.           GuiFree(Fptr);
  1128.             }
  1129.         }
  1130.    else
  1131.       {
  1132.       SetLastErr("Attempt to destroy a non-existing frame.");
  1133.       Diagnostic("DestroyFrame", EXIT, FALSE);
  1134.       return;
  1135.       }
  1136.    Diagnostic("DestroyFrame", EXIT, TRUE);
  1137.    }
  1138.  
  1139. void DestroyAllFrames(BOOL refresh)
  1140.    {
  1141.    Frame *g = Gui.FirstFrame;
  1142.    Diagnostic("DestroyAllFrames", ENTER, TRUE);
  1143.    while (g)
  1144.       {
  1145.         if (g->WidgetData->ParentControl == NULL)
  1146.             {
  1147.             DestroyFrame(g, refresh);
  1148.             /*    Destroying a frame will destroy any subframes inside it so it's not safe to assume that the
  1149.                 next frame in the list still exists. */
  1150.             g = Gui.FirstFrame;
  1151.             }
  1152.         else
  1153.             g = g->next;
  1154.       }
  1155.    Diagnostic("DestroyAllFrames", EXIT, TRUE);
  1156.    }
  1157.  
  1158. void DestroyWinFrames(GuiWindow *w, BOOL refresh)
  1159.    {
  1160.    Frame *g = Gui.FirstFrame;
  1161.    BOOL message = FALSE;
  1162.    Diagnostic("DestroyWinFrames", ENTER, TRUE);
  1163.    while (g)
  1164.       {
  1165.       if (g->button.UserData == (APTR) w && g->WidgetData->ParentControl == NULL)
  1166.          {
  1167.          DestroyFrame(g, refresh);
  1168.          message = TRUE;
  1169.             /*    Destroying a frame will destroy any sub-frames inside it so it's not safe to just continue
  1170.                 from the next frame here. */
  1171.             g = Gui.FirstFrame;
  1172.          }
  1173.         else
  1174.             g = g->next;
  1175.       }
  1176.    if (Gui.CleanupFlag && message)
  1177.       SetLastErr("Window closed before all of its frames were destroyed.");
  1178.    Diagnostic("DestroyWinFrames", EXIT, TRUE);
  1179.    }
  1180.  
  1181. void ResizeFrame(Frame *frame, int x, int y, int width, int height, BOOL eraseold)
  1182.     {
  1183.     BOOL rounded = ((frame->WidgetData->flags & SYS_FM_ROUNDED) && height >= 6 && !(frame->WidgetData->flags & FM_BORDERLESS));
  1184.     /*    If the frame is in a coloured frame then no need to blank it because the parent frame will
  1185.         blank it's entire contents. */
  1186.     if (eraseold && GetBackCol(frame->WidgetData->Parent) == GUIWIN(frame)->Win->RPort->BgPen)
  1187.         UndrawFrame(frame);
  1188.  
  1189.    /* Outer border (two structures) */
  1190.     if (rounded) // Rounded corners
  1191.         {
  1192.         /* White */
  1193.         frame->points[0] = frame->points[2] = frame->points[13] = frame->points[15] = 0;
  1194.         frame->points[1] = height - 1;
  1195.         frame->points[3] = frame->points[12] = 5;
  1196.         frame->points[4] = frame->points[6] = frame->points[9] = frame->points[11] = 1;
  1197.         frame->points[5] = frame->points[10] = 4;
  1198.         frame->points[7] = frame->points[8] = 3;
  1199.         frame->points[14] = width - 6;
  1200.  
  1201.         /* Black */
  1202.         frame->points[16] = width - 5;
  1203.         frame->points[17] = frame->points[19] = 1;
  1204.         frame->points[18] = width - 4;
  1205.         frame->points[20] = frame->points[22] = width - 2;
  1206.         frame->points[21] = 3;
  1207.         frame->points[23] = 4;
  1208.         frame->points[24] = frame->points[26] = width - 1;
  1209.         frame->points[25] = 5;
  1210.         frame->points[27] = height - 1;
  1211.         }
  1212.     else
  1213.         {
  1214.         /* White */
  1215.         frame->points[0] = frame->points[2] = frame->points[3] = frame->points[5] = 0;
  1216.         frame->points[1] = height - 1;
  1217.         frame->points[4] = width - 2;
  1218.  
  1219.         /* Black */
  1220.         frame->points[6] = 1;
  1221.         frame->points[7] = frame->points[9] = height - 1;
  1222.         frame->points[8] = frame->points[10] = width - 1;
  1223.         frame->points[11] = 0;
  1224.         }
  1225.     frame->light.Count = frame->WidgetData->flags & FM_BORDERLESS ? 0 : (rounded ? 8 : 3);
  1226.     frame->dark.Count = frame->WidgetData->flags & FM_BORDERLESS ? 0 : (rounded ? 6 : 3);
  1227.     frame->dark.XY = (rounded ? &(frame->points[16]) : &(frame->points[6]));
  1228.  
  1229.     frame->button.LeftEdge = x;
  1230.     frame->button.TopEdge  = y;
  1231.     if ((frame->WidgetData->flags & FM_LBUT) || (frame->WidgetData->flags & FM_RBUT) || (frame->WidgetData->flags & FM_DRAG))
  1232.         {
  1233.         frame->button.Width    = width;
  1234.         frame->button.Height   = height;
  1235.         }
  1236.     else
  1237.         {
  1238.         /* The frame is just being used as a holder for other controls so the gadget needs to be small
  1239.             and out of the way. */
  1240.         frame->button.Width    = 1;
  1241.         frame->button.Height   = 1;
  1242.         }
  1243.  
  1244.     if (frame->t)
  1245.         {
  1246.         TruncateIText(&frame->text, frame->t, width - 2, JUSTIFY_LEFT);
  1247.         frame->text.TopEdge  = ((height - ((GuiWindow *) frame->button.UserData)->Win->RPort->TxHeight) / 2) + 1;
  1248.         frame->text.LeftEdge = (width - IntuiTextLength(&(frame->text))) / 2;
  1249.         }
  1250.     frame->WidgetData->left = x;
  1251.     frame->WidgetData->top = y;
  1252.     frame->WidgetData->width = width;
  1253.     frame->WidgetData->height = height;
  1254.     }
  1255.  
  1256. void DisableFrame(Frame *Fptr)
  1257.    {
  1258.    Diagnostic("DisableFrame", ENTER, TRUE);
  1259.     if (Fptr && Fptr->Active && !Fptr->WidgetData->ParentControl) // Don't disable the frame if it's part of another control.
  1260.         {
  1261.         GuiWindow *wptr = (GuiWindow *) Fptr->button.UserData;
  1262.  
  1263.         if (Fptr->hidden == 0)
  1264.             DisableGadget(&Fptr->button, wptr->Win, TRUE);
  1265.         else // The button is hidden
  1266.             Fptr->button.Flags |= GFLG_DISABLED;
  1267.        Fptr->Active = FALSE;
  1268.        Diagnostic("DisableFrame", EXIT, TRUE);
  1269.         }
  1270.     else
  1271.        Diagnostic("DisableFrame", EXIT, FALSE);
  1272.    }
  1273.  
  1274. void DisableAllFrames(void)
  1275.    {
  1276.    Frame *ggl = Gui.FirstFrame;
  1277.    Diagnostic("DisableAllFrames", ENTER, TRUE);
  1278.    while (ggl)
  1279.       {
  1280.       DisableFrame(ggl);
  1281.       ggl = ggl->next;
  1282.       }
  1283.    Diagnostic("DisableAllFrames", EXIT, TRUE);
  1284.    }
  1285.  
  1286. void DisableWinFrames(GuiWindow *w)
  1287.    {
  1288.    Frame *f = Gui.FirstFrame;
  1289.    Diagnostic("DisableWinFrames", ENTER, TRUE);
  1290.    while (f)
  1291.          {
  1292.          if (f->button.UserData == (APTR) w)
  1293.             DisableFrame(f);
  1294.       f = f->next;
  1295.          }
  1296.    Diagnostic("DisableWinFrames", EXIT, TRUE);
  1297.    }
  1298.  
  1299. void EnableFrame(Frame *Fptr)
  1300.    {
  1301.    Diagnostic("EnableFrame", ENTER, TRUE);
  1302.     if (Fptr && (!Fptr->Active) && !Fptr->WidgetData->ParentControl) // Don't enable the frame if it's part of another control.
  1303.         {
  1304.         /* Only the border will be refreshed, leaving the rest of the frame still looking shaded and
  1305.             disabled.  Clear it here before refreshing. */
  1306.         if (Fptr->hidden == 0)
  1307.             {
  1308.             GuiWindow *wptr = (GuiWindow *) Fptr->button.UserData;
  1309.  
  1310.             AreaColFill(wptr->Win->RPort, Fptr->button.LeftEdge, Fptr->button.TopEdge, Fptr->points[8] + 1,
  1311.                     Fptr->points[1] + 1, GetBackCol(Fptr->WidgetData->Parent));
  1312.             EnableGadget(&(Fptr->button), wptr->Win, TRUE);
  1313.             }
  1314.         else // The button is hidden
  1315.             Fptr->button.Flags ^= GFLG_DISABLED;
  1316.        Fptr->Active = TRUE;
  1317.        Diagnostic("EnableFrame", EXIT, TRUE);
  1318.         }
  1319.     else
  1320.         Diagnostic("EnableFrame", EXIT, FALSE);
  1321.    }
  1322.  
  1323. void EnableAllFrames(void)
  1324.    {
  1325.    Frame *ggl = Gui.FirstFrame;
  1326.    Diagnostic("EnableAllFrames", ENTER, TRUE);
  1327.    while (ggl)
  1328.       {
  1329.       EnableFrame(ggl);
  1330.       ggl = ggl->next;
  1331.       }
  1332.    Diagnostic("EnableAllFrames", EXIT, TRUE);
  1333.    }
  1334.  
  1335. void EnableWinFrames(GuiWindow *w)
  1336.    {
  1337.    Frame *f = Gui.FirstFrame;
  1338.    Diagnostic("EnableWinFrames", ENTER, TRUE);
  1339.    while (f)
  1340.          {
  1341.       if (f->button.UserData == (APTR) w)
  1342.             EnableFrame(f);
  1343.          f = f->next;
  1344.       }
  1345.    Diagnostic("EnableWinFrames", EXIT, TRUE);
  1346.    }
  1347.  
  1348. void FOXLIB SetFrameDragPointer(REGA0 Frame *Fptr, REGA1 unsigned short *DragPointer, REGD0 int width, REGD1 int height, REGD2 int xoffset, REGD3 int yoffset)
  1349. {
  1350.     Fptr->DragPointer = DragPointer;
  1351.     Fptr->PointerWidth = width;
  1352.     Fptr->PointerHeight = height;
  1353.     Fptr->PointerXOffset = xoffset;
  1354.     Fptr->PointerYOffset = yoffset;
  1355. }
  1356.  
  1357. Frame* FOXLIB MakeFrame(REGA0 void *Parent, REGA1 char *name, REGD0 int left, REGD1 int top, REGD2 int width, REGD3 int height, REGA2 struct Border *cb, REGA3 int (* __far __stdargs callfn) (Frame*, short, short, short, void**), REGD4 short flags, REGD5 void *extension)
  1358.    {
  1359.     Frame *Fptr;
  1360.     GuiWindow *Wptr;
  1361.     Frame *ParentFrame = NULL;
  1362.    Diagnostic("MakeFrame", ENTER, TRUE);
  1363.  
  1364.     if (!Parent)
  1365.         {
  1366.       Diagnostic("MakeFrame", EXIT, FALSE);
  1367.       return NULL;
  1368.         }
  1369.    if ((Fptr = (Frame *) GuiMalloc(sizeof(Frame), 0)) == NULL)
  1370.       {
  1371.       Diagnostic("MakeFrame", EXIT, FALSE);
  1372.       return NULL;
  1373.       }
  1374.    if ((Fptr->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), 0)) == NULL)
  1375.       {
  1376.         GuiFree(Fptr);
  1377.       Diagnostic("MakeFrame", EXIT, FALSE);
  1378.       return NULL;
  1379.       }
  1380.     Fptr->DragPointer = NULL;
  1381.     if (cb)
  1382.         {
  1383.         int l;
  1384.         if ((Fptr->cbCopy = (short *) GuiMalloc(cb->Count * 2 * sizeof(short), 0)) == NULL)
  1385.             {
  1386.             GuiFree(Fptr->WidgetData);
  1387.             GuiFree(Fptr);
  1388.             Diagnostic("MakeFrame", EXIT, FALSE);
  1389.             return NULL;
  1390.             }
  1391.         for (l = 0; l < 2 * cb->Count; l++)
  1392.             Fptr->cbCopy[l] = cb->XY[l];
  1393.         }
  1394.     else
  1395.         Fptr->cbCopy = NULL;
  1396.  
  1397.     if (!ISGUIWINDOW(Parent))
  1398.         {
  1399.         ParentFrame = (Frame *) Parent;
  1400.         left += ParentFrame->button.LeftEdge;
  1401.         top += ParentFrame->button.TopEdge;
  1402.         Wptr = (GuiWindow *) ParentFrame->button.UserData;
  1403.         }
  1404.     else
  1405.         Wptr = (GuiWindow *) Parent;
  1406.  
  1407.     Fptr->WidgetData->ObjectType = FrameObject;
  1408.     if (ParentFrame && (flags & S_AUTO_SIZE) && !(ParentFrame->WidgetData->flags & S_AUTO_SIZE))
  1409.         flags ^= S_AUTO_SIZE;
  1410.     Fptr->WidgetData->flags = flags;
  1411.     if (ParentFrame && ParentFrame->hidden != 0)
  1412.         Fptr->hidden = -1;
  1413.     else
  1414.         Fptr->hidden = 0;
  1415.     Fptr->WidgetData->Parent = Parent;
  1416.     Fptr->WidgetData->ParentControl = NULL;
  1417.     Fptr->WidgetData->NextWidget = NULL;
  1418.     Fptr->WidgetData->ChildWidget = NULL;
  1419.  
  1420.     if (flags & S_AUTO_SIZE)
  1421.         {
  1422.         if (!(Fptr->WidgetData->os = (OriginalSize *) GuiMalloc(sizeof(OriginalSize), 0)))
  1423.             {
  1424.             if (Fptr->cbCopy)
  1425.                 GuiFree(Fptr->cbCopy);
  1426.             GuiFree(Fptr->WidgetData);
  1427.             GuiFree(Fptr);
  1428.             Diagnostic("MakeFrame", EXIT, FALSE);
  1429.             return NULL;
  1430.             }
  1431.         Fptr->WidgetData->os->left = left;
  1432.         Fptr->WidgetData->os->top = top;
  1433.         Fptr->WidgetData->os->width = width;
  1434.         Fptr->WidgetData->os->height = height;
  1435.         }
  1436.     else
  1437.         Fptr->WidgetData->os = NULL;
  1438.  
  1439.     if (name && strlen(name))
  1440.         {
  1441.         if (!(Fptr->t = (char *) GuiMalloc((strlen(name) + 2) * sizeof(char), 0)))
  1442.             {
  1443.             if (Fptr->WidgetData->os)
  1444.                 GuiFree(Fptr->WidgetData->os);
  1445.             if (Fptr->cbCopy)
  1446.                 GuiFree(Fptr->cbCopy);
  1447.             GuiFree(Fptr->WidgetData);
  1448.             GuiFree(Fptr);
  1449.             Diagnostic("MakeFrame", EXIT, FALSE);
  1450.             return NULL;
  1451.             }
  1452.         Fptr->t[0] = 0;
  1453.         strcpy(&Fptr->t[1], name);
  1454.         Fptr->text.ITextFont = CopyFont(&GuiFont);
  1455.         Fptr->text.FrontPen  = Gui.TextCol;
  1456.         Fptr->text.DrawMode  = JAM1;
  1457.         Fptr->text.IText = &Fptr->t[1];
  1458.         Fptr->text.NextText = NULL;
  1459.         }
  1460.     else
  1461.         {
  1462.         Fptr->t = NULL;
  1463.         Fptr->text.ITextFont = NULL;
  1464.         }
  1465.  
  1466.    Fptr->light.LeftEdge   = Fptr->light.TopEdge = 0;
  1467.    Fptr->light.XY         = Fptr->points;
  1468.    Fptr->light.NextBorder = &(Fptr->dark);
  1469.    Fptr->light.FrontPen   = Gui.HiPen;
  1470.     Fptr->light.BackPen    = Gui.BackCol; // Ignored by Intuition - just for storage.
  1471.    Fptr->light.DrawMode   = JAM1;
  1472.    Fptr->dark.LeftEdge    = Fptr->dark.TopEdge = 0;
  1473.    Fptr->dark.NextBorder  = cb;
  1474.    Fptr->dark.FrontPen    = Gui.LoPen;
  1475.    Fptr->dark.DrawMode    = JAM1;
  1476.  
  1477.    Fptr->button.NextGadget   = NULL;
  1478.    Fptr->button.Flags        = GADGHNONE;
  1479.     Fptr->button.Activation   = 0;
  1480.     if (flags & FM_LBUT)
  1481.         Fptr->button.Activation    |= GACT_RELVERIFY;
  1482.    if (flags & FM_DRAG)
  1483.         Fptr->button.Activation |= GACT_IMMEDIATE | GACT_RELVERIFY | GACT_FOLLOWMOUSE;
  1484.    Fptr->button.GadgetType   = BOOLGADGET;
  1485.    Fptr->button.GadgetRender = (APTR) &(Fptr->light);
  1486.    Fptr->button.SelectRender = (APTR) NULL;
  1487.     Fptr->button.GadgetText   = Fptr->t ? &(Fptr->text) : NULL;
  1488.    Fptr->button.GadgetID     = 0;
  1489.    Fptr->button.UserData     = (APTR) Wptr;
  1490.    Fptr->Callfn = callfn;
  1491.    Fptr->Active = TRUE;
  1492.     Fptr->bitmap = NULL;
  1493.  
  1494.     ResizeFrame(Fptr, left, top, width, height, FALSE);
  1495.  
  1496.     /* The frame has to be added to the end of the list so that they are
  1497.         refreshed in the right order when a window is resized. */
  1498.     Fptr->next = NULL;
  1499.     if (!Gui.FirstFrame)
  1500.         Gui.FirstFrame = Fptr;
  1501.     else
  1502.         {
  1503.         Frame *f = Gui.FirstFrame;
  1504.         while (f->next)
  1505.             f = f->next;
  1506.         f->next = Fptr;
  1507.         }
  1508.     if (Fptr->hidden == 0)
  1509.         {
  1510.         if (!(flags & FM_CLEAR))
  1511.             AreaColFill(Wptr->Win->RPort, left, top, width, height, Gui.BackCol);
  1512.        AddGadget(Wptr->Win, &(Fptr->button), -1);
  1513.         RefreshGadgets(&(Fptr->button), Wptr->Win, NULL);
  1514.         }
  1515.     Diagnostic("MakeFrame", EXIT, TRUE);
  1516.    return Fptr;
  1517.    }
  1518.  
  1519. void DisableTabControl(TabControl *tc)
  1520.     {
  1521.     Diagnostic("DisableTabControl", ENTER, TRUE);
  1522.     if (tc)
  1523.         {
  1524.         Tab *t = tc->FirstTab;
  1525.  
  1526.         while (t)
  1527.             {
  1528.             if (t->pb)
  1529.                 {
  1530.                 Widget *ParentControl = t->pb->WidgetData->ParentControl;
  1531.                 // Pretend it's not part of another control or we can't disable it.
  1532.                 t->pb->WidgetData->ParentControl = NULL;
  1533.                 DisableFrame(t->pb);
  1534.                 t->pb->WidgetData->ParentControl = ParentControl;
  1535.                 }
  1536.             t = t->next;
  1537.             }
  1538.         }
  1539.     Diagnostic("DisableTabControl", EXIT, tc != NULL);
  1540.     }
  1541.  
  1542. void EnableTabControl(TabControl *tc)
  1543.     {
  1544.     Diagnostic("EnableTabControl", ENTER, TRUE);
  1545.     if (tc)
  1546.         {
  1547.         Tab *t = tc->FirstTab;
  1548.  
  1549.         while (t)
  1550.             {
  1551.             if (t->pb)
  1552.                 {
  1553.                 Widget *ParentControl = t->pb->WidgetData->ParentControl;
  1554.                 // Pretend it's not part of another control or we can't enable it.
  1555.                 t->pb->WidgetData->ParentControl = NULL;
  1556.                 EnableFrame(t->pb);
  1557.                 t->pb->WidgetData->ParentControl = ParentControl;
  1558.                 }
  1559.             t = t->next;
  1560.             }
  1561.         }
  1562.     Diagnostic("EnableTabControl", EXIT, tc != NULL);
  1563.     }
  1564.  
  1565. BOOL HideTabControl(TabControl *tc)
  1566.     {
  1567.     Diagnostic("HideTabControl", ENTER, TRUE);
  1568.     if (tc)
  1569.         {
  1570.         Tab *t = tc->FirstTab;
  1571.         BOOL retval = TRUE;
  1572.  
  1573.         while (t)
  1574.             {
  1575.             if (t->pb)
  1576.                 retval = retval && HideFrame(t->pb);
  1577.             if (t->frame)
  1578.                 retval = retval && HideFrame(t->frame);
  1579.             t = t->next;
  1580.             }
  1581.         return retval;
  1582.         }
  1583.     else
  1584.         return FALSE;
  1585.     Diagnostic("HideTabControl", EXIT, tc != NULL);
  1586.     }
  1587.  
  1588. BOOL ShowTabControl(TabControl *tc)
  1589.     {
  1590.     Diagnostic("ShowTabControl", ENTER, TRUE);
  1591.     if (tc)
  1592.         {
  1593.         Tab *t = tc->FirstTab;
  1594.         BOOL retval = TRUE;
  1595.  
  1596.         while (t)
  1597.             {
  1598.             if (t->pb)
  1599.                 retval = retval && ShowFrame(t->pb);
  1600.             if (t->frame && t == tc->SelectedTab) // Only show the frame for the selected button.
  1601.                 retval = retval && ShowFrame(t->frame);
  1602.             t = t->next;
  1603.             }
  1604.         return retval;
  1605.         }
  1606.     else
  1607.         return FALSE;
  1608.     Diagnostic("ShowTabControl", EXIT, tc != NULL);
  1609.     }
  1610.  
  1611. //int TabButtFn(PushButton *pb)
  1612. int TabButtFn(Frame *pb, short Event, short x, short y, void **data)
  1613.     {
  1614.     if (Event == FM_LBUT)
  1615.         {
  1616.         GuiWindow *win = (GuiWindow *) pb->button.UserData;
  1617.         TabControl *tc = (TabControl *) pb->WidgetData->ParentControl;
  1618.         short width;
  1619.         Tab *t = tc->SelectedTab;
  1620.  
  1621.         if (t->pb == pb) // The button clicked is already the selected tab
  1622.             return GUI_CONTINUE;
  1623.         HideFrame(t->frame);
  1624.         t->frame->dark.NextBorder = NULL;
  1625.         RefreshGList(&t->pb->button, win->Win, NULL, 1);
  1626.  
  1627.         t = tc->FirstTab;
  1628.         while (t)
  1629.             {
  1630.             if (t->pb == pb)
  1631.                 break;
  1632.             t = t->next;
  1633.             }
  1634.         tc->SelectedTab = t;
  1635.         width = pb->button.Width - (t->next == NULL ? 2 : 1);
  1636.         tc->FramePoints[0] = pb->button.LeftEdge - t->frame->button.LeftEdge + 1;
  1637.         tc->FramePoints[2] = tc->FramePoints[0] + width - 1;
  1638.         t->frame->dark.NextBorder = &tc->CustomFrameBorder;
  1639.         ShowFrame(t->frame);
  1640.         RefreshGList(&pb->button, win->Win, NULL, 1);
  1641.         if (!tc->Callfn)
  1642.             return GUI_CONTINUE;
  1643.         else
  1644.             return (*tc->Callfn)(pb);
  1645.         }
  1646.         return GUI_CONTINUE;
  1647.     }
  1648.  
  1649. void DestroyTabControl(TabControl *tc, BOOL refresh)
  1650.     {
  1651.     Diagnostic("DestroyTabControl", ENTER, TRUE);
  1652.     if (tc)
  1653.         {
  1654.         Frame *Child; // Could be any object type
  1655.         Tab *t = tc->FirstTab, *nt;
  1656.  
  1657.         while (t)
  1658.             {
  1659.             nt = t->next;
  1660.             if (t->pb)
  1661.                 {
  1662.                 // Pretend the button is not part of another control or we can't destroy it.
  1663.                 t->pb->WidgetData->ParentControl = NULL;
  1664.                 DestroyFrame(t->pb, refresh);
  1665.                 }
  1666.             if (t->frame)
  1667.                 {
  1668.                 // Pretend the frame is not part of another control or we can't destroy it.
  1669.                 t->frame->WidgetData->ParentControl = NULL;
  1670.                 DestroyFrame(t->frame, refresh);
  1671.                 }
  1672.             GuiFree(t);
  1673.             t = nt;
  1674.             }
  1675.         if (Gui.FirstTabControl == tc)
  1676.             Gui.FirstTabControl = tc->next;
  1677.         else
  1678.             {
  1679.             TabControl *tcp = Gui.FirstTabControl;
  1680.             while (tcp->next && tcp->next != tc)
  1681.                 tcp = tcp->next;
  1682.             tcp->next = tc->next;
  1683.             }
  1684.         Child = tc->WidgetData->ChildWidget;
  1685.         while (Child)
  1686.             {
  1687.             void *next = Child->WidgetData->NextWidget;
  1688.             Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  1689.             Destroy(Child, refresh);
  1690.             Child = next;
  1691.             }
  1692.         GuiFree(tc->WidgetData);
  1693.         GuiFree(tc);
  1694.         }
  1695.     Diagnostic("DestroyTabControl", EXIT, tc != NULL);
  1696.     }
  1697.  
  1698. void DestroyWinTabControls(GuiWindow *win, BOOL refresh)
  1699.     {
  1700.     TabControl *tc = Gui.FirstTabControl;
  1701.     Diagnostic("DestroyWinTabControls", ENTER, TRUE);
  1702.     if (!win)
  1703.         {
  1704.         Diagnostic("DestroyWinTabControls", EXIT, FALSE);
  1705.         return;
  1706.         }
  1707.     while (tc)
  1708.         {
  1709.         if (tc->FirstTab && tc->FirstTab->frame && (GuiWindow *) tc->FirstTab->frame->button.UserData == win)
  1710.             {
  1711.             DestroyTabControl(tc, refresh);
  1712.             /*    There could be tab controls within tab controls so it's not safe to assume that the next one
  1713.                 in the list stll exists. */
  1714.             tc = Gui.FirstTabControl;
  1715.             }
  1716.         else
  1717.             tc = tc->next;
  1718.         }
  1719.     Diagnostic("DestroyWinTabControls", EXIT, TRUE);
  1720.     }
  1721.  
  1722. void DestroyAllTabControls(BOOL refresh)
  1723.     {
  1724.     TabControl *tc = Gui.FirstTabControl;
  1725.     Diagnostic("DestroyAllTabControls", ENTER, TRUE);
  1726.     while (tc)
  1727.         {
  1728.         DestroyTabControl(tc, refresh);
  1729.         /*    There could be tab controls within tab controls so it's not safe to assume that the next one
  1730.             in the list stll exists. */
  1731.         tc = Gui.FirstTabControl;
  1732.         }
  1733.     Diagnostic("DestroyAllTabControls", EXIT, TRUE);
  1734.     }
  1735.  
  1736. /* Returns a pointer to Frame frameno in the TabControl tc, or NULL if tc is NULL or if frameno is too
  1737.     high.  Note that frames are numbered starting at zero. */
  1738. Frame* FOXLIB TabControlFrame(REGA0 TabControl *tc, REGD0 int frameno)
  1739.     {
  1740.     Tab *t;
  1741.     int n = 0;
  1742.     if (!tc)
  1743.         return NULL;
  1744.     t = tc->FirstTab;
  1745.     while (n < frameno && t)
  1746.         {
  1747.         t = t->next;
  1748.         n++;
  1749.         }
  1750.     if (t)
  1751.         return t->frame;
  1752.     else
  1753.         return NULL;
  1754.     }
  1755.  
  1756. BOOL SetUpTab(TabControl *tc, Tab *t, void *Parent, int left, int top, int width, int height, int tableft, int tabheight, int tabwidth, char *caption, short flags, struct Border *customborder, BOOL hidden, int (* __far __stdargs framefn) (Frame*, short, short, short, void**))
  1757.     {
  1758.     /* Make the button before the frame.  Ideally all of the buttons should be made before all of the
  1759.         frames because that's the order they end up in once any button has been pressed (because hiding
  1760.         a frame removes it from the gadget list and showing a frame adds it to the end). */
  1761.     if ((t->pb = MakeFrame(Parent, caption, tableft, top, tabwidth, tabheight, NULL,
  1762.             TabButtFn, FM_LBUT | SYS_FM_ROUNDED | flags, NULL)) == NULL)
  1763.         {
  1764.         DestroyTabControl(tc, TRUE);
  1765.         return FALSE;
  1766.         }
  1767.     t->pb->WidgetData->ParentControl = tc;
  1768.     if (customborder)
  1769.         {
  1770.         tc->FramePoints[0] = tableft - left + 1;
  1771.         tc->FramePoints[2] = tc->FramePoints[0] + t->pb->button.Width - (t->next == NULL ? 3 : 2);
  1772.         }
  1773.     if (flags & TC_FOXED)
  1774.         flags |= FM_LBUT | FM_DRAG | FM_DRAGOUTLINE | FM_DROP;
  1775.     if ((t->frame = MakeFrame(Parent, NULL, left, top + tabheight, width, height, customborder, framefn,
  1776.             flags, NULL)) == NULL)
  1777.         {
  1778.         DestroyTabControl(tc, TRUE);
  1779.         return FALSE;
  1780.         }
  1781.     if (hidden)
  1782.         HideFrame(t->frame);
  1783.     t->frame->WidgetData->ParentControl = tc;
  1784.     return TRUE;
  1785.     }
  1786.  
  1787. TabControl* FOXLIB MakeTabControlArray(REGA0 void *Parent, REGD0 int left, REGD1 int top, REGD2 int width, REGD3 int height,
  1788.         REGD4 int tabheight, REGD5 short flags, REGA1 int *tabwidth, REGA2 char **caption,
  1789.         REGA3 TabControlExtension *ext)
  1790.     {
  1791.     TabControl *tc;
  1792.     short n;
  1793.     Tab *last = NULL;
  1794.     int tableft = left, seltableft;
  1795.     GuiWindow *Wptr;
  1796.     int tabno = 0;
  1797.     int (* __far __stdargs callfn) (Frame*) = NULL;
  1798.     int (* __far __stdargs framefn) (Frame*, short, short, short, void**) = NULL;
  1799.  
  1800.     Diagnostic("MakeTabControlArray", ENTER, TRUE);
  1801.     if (!Parent)
  1802.         {
  1803.         Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1804.         return NULL;
  1805.         }
  1806.     if (ext)
  1807.         {
  1808.         callfn = ext->callfn;
  1809.         tabno = ext->tabselected;
  1810.         framefn = ext->framefn;
  1811.         }
  1812.     if (!ISGUIWINDOW(Parent))
  1813.         Wptr = (GuiWindow *) ((Frame *) Parent)->button.UserData;
  1814.     else
  1815.         Wptr = (GuiWindow *) Parent;
  1816.     if ((tc = (TabControl*) GuiMalloc(sizeof(TabControl), 0)) == NULL)
  1817.         {
  1818.         Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1819.         return NULL;
  1820.         }
  1821.     if ((tc->WidgetData = (Widget*) GuiMalloc(sizeof(Widget), 0)) == NULL)
  1822.         {
  1823.         GuiFree(tc);
  1824.         Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1825.         return NULL;
  1826.         }
  1827.     tc->Callfn = callfn;
  1828.     tc->WidgetData->Parent = Parent;
  1829.     tc->WidgetData->ObjectType = TabControlObject;
  1830.     tc->WidgetData->left = left;
  1831.     tc->WidgetData->top = top;
  1832.     tc->WidgetData->width = width;
  1833.     tc->WidgetData->height = height + tabheight;
  1834.     tc->WidgetData->NextWidget = NULL;
  1835.     tc->WidgetData->ChildWidget = NULL;
  1836.     tc->FirstTab = NULL;
  1837.     tc->next = NULL;
  1838.     if (flags & FM_CLEAR)
  1839.         tc->CustomFrameBorder.FrontPen = GetBackCol(Parent);
  1840.     else
  1841.         tc->CustomFrameBorder.FrontPen = Gui.BackCol;
  1842.     tc->CustomFrameBorder.LeftEdge = tc->CustomFrameBorder.TopEdge = 0;
  1843.     tc->CustomFrameBorder.DrawMode = JAM1;
  1844.     tc->CustomFrameBorder.XY = tc->FramePoints;
  1845.     tc->CustomFrameBorder.Count = 2;
  1846.     tc->CustomFrameBorder.NextBorder = NULL;
  1847.     tc->FramePoints[1] = tc->FramePoints[3] = 0;
  1848.     for (n = 0; tabwidth[n] > 0; n++)
  1849.         {
  1850.         Tab *t = (Tab*) GuiMalloc(sizeof(Tab), 0);
  1851.         if (!t)
  1852.             {
  1853.             DestroyTabControl(tc, TRUE);
  1854.             Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1855.             return NULL;
  1856.             }
  1857.         t->next = NULL;
  1858.         t->pb = NULL;
  1859.         t->frame = NULL;
  1860.         if (n != tabno) // Make the displayed frame last so that it doesn't need refreshing.
  1861.             {
  1862.             if (!SetUpTab(tc, t, Parent, left, top, width, height, tableft, tabheight, tabwidth[n], caption[n], flags, NULL, TRUE, framefn))
  1863.                 {
  1864.                 Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1865.                 return NULL;
  1866.                 }
  1867.             }
  1868.         else
  1869.             {
  1870.             tc->SelectedTab = t;
  1871.             seltableft = tableft;
  1872.             }
  1873.         if (last)
  1874.             last->next = t;
  1875.         else
  1876.             tc->FirstTab = t;
  1877.         last = t;
  1878.         tableft += tabwidth[n];
  1879.         }
  1880.  
  1881.     if (!SetUpTab(tc, tc->SelectedTab, Parent, left, top, width, height, seltableft, tabheight, tabwidth[tabno], caption[tabno], flags, &tc->CustomFrameBorder, FALSE, framefn))
  1882.         {
  1883.         Diagnostic("MakeTabControlArray", EXIT, FALSE);
  1884.         return NULL;
  1885.         }
  1886.  
  1887.     tc->next = Gui.FirstTabControl;
  1888.     Gui.FirstTabControl = tc;
  1889.     Diagnostic("MakeTabControlArray", EXIT, TRUE);
  1890.     return tc;
  1891.     }
  1892.  
  1893. TabControl*
  1894. #ifdef TEMPORARY
  1895. FOXLIB
  1896. #endif
  1897. MakeTabControl(void *Parent, int left, int top, int width, int height, int tabheight, short flags, int numtabs, ...)
  1898.     {
  1899.     va_list argptr;
  1900.     TabControl *tc;
  1901.     short n;
  1902.     Tab *last = NULL;
  1903.     int firstwidth, tableft = left;
  1904.     char *firstcaption;
  1905.     GuiWindow *Wptr;
  1906.  
  1907.     Diagnostic("MakeTabControl", ENTER, TRUE);
  1908.     va_start(argptr, numtabs);
  1909.     if (!Parent)
  1910.         {
  1911.         Diagnostic("MakeTabControl", EXIT, FALSE);
  1912.         va_end(argptr);
  1913.         return NULL;
  1914.         }
  1915.     if (!ISGUIWINDOW(Parent))
  1916.         Wptr = (GuiWindow *) ((Frame *) Parent)->button.UserData;
  1917.     else
  1918.         Wptr = (GuiWindow *) Parent;
  1919.     if ((tc = (TabControl*) GuiMalloc(sizeof(TabControl), 0)) == NULL)
  1920.         {
  1921.         Diagnostic("MakeTabControl", EXIT, FALSE);
  1922.         va_end(argptr);
  1923.         return NULL;
  1924.         }
  1925.     if ((tc->WidgetData = (Widget*) GuiMalloc(sizeof(Widget), 0)) == NULL)
  1926.         {
  1927.         GuiFree(tc);
  1928.         Diagnostic("MakeTabControl", EXIT, FALSE);
  1929.         va_end(argptr);
  1930.         return NULL;
  1931.         }
  1932.     tc->Callfn = NULL;
  1933.     tc->WidgetData->Parent = Parent;
  1934.     tc->WidgetData->ObjectType = TabControlObject;
  1935.     tc->FirstTab = NULL;
  1936.     tc->next = NULL;
  1937.     if (flags & FM_CLEAR)
  1938.         tc->CustomFrameBorder.FrontPen = GetBackCol(Parent);
  1939.     else
  1940.         tc->CustomFrameBorder.FrontPen = Gui.BackCol;
  1941.     tc->CustomFrameBorder.LeftEdge = tc->CustomFrameBorder.TopEdge = 0;
  1942.     tc->CustomFrameBorder.DrawMode = JAM1;
  1943.     tc->CustomFrameBorder.XY = tc->FramePoints;
  1944.     tc->CustomFrameBorder.Count = 2;
  1945.     tc->CustomFrameBorder.NextBorder = NULL;
  1946.     tc->FramePoints[0] = 1;
  1947.     tc->FramePoints[1] = tc->FramePoints[3] = 0;
  1948.     for (n = 0; n < numtabs; n++)
  1949.         {
  1950.         int tabwidth = va_arg(argptr, int);
  1951.         char *caption = va_arg(argptr, char*);
  1952.         Tab *t = (Tab*) GuiMalloc(sizeof(Tab), 0);
  1953.         if (!t)
  1954.             {
  1955.             DestroyTabControl(tc, TRUE);
  1956.             Diagnostic("MakeTabControl", EXIT, FALSE);
  1957.             va_end(argptr);
  1958.             return NULL;
  1959.             }
  1960.         t->next = NULL;
  1961.         t->pb = NULL;
  1962.         t->frame = NULL;
  1963.         if (n > 0) // Make the first frame last so that it doesn't need refreshing.
  1964.             {
  1965.             if (!SetUpTab(tc, t, Parent, left, top, width, height, tableft, tabheight, tabwidth, caption, flags, NULL, TRUE, NULL))
  1966.                 {
  1967.                 va_end(argptr);
  1968.                 Diagnostic("MakeTabControl", EXIT, FALSE);
  1969.                 return NULL;
  1970.                 }
  1971.             }
  1972.         else
  1973.             {
  1974.             tc->FramePoints[2] = tabwidth - 1;
  1975.             firstcaption = caption;
  1976.             firstwidth = tabwidth;
  1977.             }
  1978.         if (last)
  1979.             last->next = t;
  1980.         else
  1981.             tc->FirstTab = tc->SelectedTab = t;
  1982.         last = t;
  1983.         tableft += tabwidth;
  1984.         }
  1985.     va_end(argptr);
  1986.  
  1987.     if (!SetUpTab(tc, tc->FirstTab, Parent, left, top, width, height, left, tabheight, firstwidth, firstcaption, flags, &tc->CustomFrameBorder, FALSE, NULL))
  1988.         {
  1989.         Diagnostic("MakeTabControl", EXIT, FALSE);
  1990.         return NULL;
  1991.         }
  1992.  
  1993.     tc->next = Gui.FirstTabControl;
  1994.     Gui.FirstTabControl = tc;
  1995.     Diagnostic("MakeTabControl", EXIT, TRUE);
  1996.     return tc;
  1997.     }
  1998.